package hu.mapro.gamelib;

import java.util.PriorityQueue;

import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.World;

public class WorldSession implements Session {

	public float MAX_STEP = 0.1f;
	public float FIX_STEP = 1 / 300f;
	public int BOX_VELOCITY_ITERATIONS=6;
	public int BOX_POSITION_ITERATIONS=3;

	public final OrthographicCamera camera;
	public final World world;
	public final Resizer resizer;
	public final Box2DDebugRenderer debugRenderer;
	
	public WorldSession(OrthographicCamera camera, Resizer resizer, World world) {
		super();
		this.camera = camera;
		this.resizer = resizer;
		this.world = world;
		
		debugRenderer = new Box2DDebugRenderer() {
//			@Override
//			protected void renderBody(Body body) {
//				if (body.getType() != BodyType.StaticBody) {
//					super.renderBody(body);
//				}
//			}
		};
		debugRenderer.setDrawJoints(false);
	}

	public float elapsedTime = 0;
	public float fixStepAccumulator = 0;
	final PriorityQueue<TimedTask> timedTasks = new PriorityQueue<TimedTask>();
	
	
	@Override
	public void resize(int width, int height) {
		resizer.resize(this, width, height);
	}

	@Override
	public void update(float delta) {
		if (delta > MAX_STEP)
			delta = MAX_STEP;

		fixStepAccumulator += delta;
		elapsedTime += FIX_STEP;
		while (fixStepAccumulator > FIX_STEP) {
			world.step(FIX_STEP, BOX_VELOCITY_ITERATIONS, BOX_POSITION_ITERATIONS);

			fixStepAccumulator -= FIX_STEP;
		}
		
		while (true) {
			TimedTask task = timedTasks.peek();
			if (task == null || task.scheduled < elapsedTime)
				break;
			timedTasks.poll();
			task.runnable.run();
		}
	}

	@Override
	public void draw() {
		drawGame();
		drawDebug();
	}

	protected void drawGame() {
	}
	
	protected void drawDebug() {
		debugRenderer.render(world, camera.combined);
	}

	@Override
	public void dispose() {
		debugRenderer.dispose();
	}

	public void resizeFixedWidth(float fixedWidth, int width, int height) {
		camera.zoom = fixedWidth / width;
		camera.setToOrtho(false, width, height);
	}
	
	public interface Resizer {
		void resize(WorldSession game, int width, int height);
	}
	
	public static Resizer fixedWidth(final float fixedWidth) {
		return new Resizer() {
			@Override
			public void resize(WorldSession game, int width, int height) {
				game.resizeFixedWidth(fixedWidth, width, height);
			}
		};
	}

	public class TimedTask implements Comparable<TimedTask> {

		final float scheduled;
		final Runnable runnable;

		public TimedTask(float scheduled, Runnable runnable) {
			super();
			this.scheduled = scheduled;
			this.runnable = runnable;
		}

		@Override
		public int compareTo(TimedTask o) {
			return Float.compare(scheduled, o.scheduled);
		}

	}

	public void scheduleDelayed(float delay, Runnable task) {
		timedTasks.add(new TimedTask(elapsedTime + delay, task));
	}

	@Override
	public void pause() {
	}

	@Override
	public void play() {
	}
	
}
